#ifndef __LIBCOMMON_BUDDY_H__
#define __LIBCOMMON_BUDDY_H__

/* Define HOST_TEST to 1 so you can build a stand alone self-tester */
#if HOST_TEST

typedef unsigned int uint32_t;

static __inline uint32_t
bsf(uint32_t n)
{
	 uint32_t result;
	 __asm __volatile("bsf %1, %0"
					  : "=r" (result)
					  : "r" (n));
	 return result;
}

static __inline uint32_t
bsr(uint32_t n)
{
	 uint32_t result;
	 __asm __volatile("bsr %1, %0"
					  : "=r" (result)
					  : "r" (n));
	 return result;
}

#include <stdlib.h>
#include <stdio.h>

#else

#include <global/header/types.h>
#include <global/header/x86.h>

#endif

struct buddy_node_s
{
	 unsigned int type   : 8;
	 unsigned int status : 8;
	 unsigned int bitmap : 8;
	 unsigned int next   : 20;
	 unsigned int prev   : 20;
} __attribute__((packed));

struct buddy_context_s
{
	 /* Should be initialized outside before buddy_build {{{ */
	 struct buddy_node_s *node;
	 /* }}} */
	 
	 int clist[20];
	 int slist[4];

	 uint32_t clist_bm;
	 uint32_t slist_bm;
	 
	 int node_count;
	 int clist_count;
};

#define BUDDY_CALC_ARRAY_SIZE(num)  (((((num) - 1) | 3) + 1) << 2)
#define BUDDY_CALC_CLIST_COUNT(num) (bsr(num) > 1 ? (bsr(num) - 1) : 0)
#define BUDDY_CALC_NODE_COUNT(num)  ((((((num) - 1) | 3) + 1) >> 1) - 1)

typedef int(*buddy_initial_is_free_f)(int num);

void buddy_init(void);
int  buddy_build(struct buddy_context_s *ctx, int num, buddy_initial_is_free_f config);
int  buddy_alloc(struct buddy_context_s *ctx, int num);
/* Return the block size */
int  buddy_free(struct buddy_context_s *ctx,  int start);

#endif
